package com.cooldatasoft.currency.util;

import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.Date;
import java.util.concurrent.Callable;

import lombok.extern.slf4j.Slf4j;

import com.cooldatasoft.currency.data.ExchangeRate;
import com.google.gson.Gson;

@Slf4j
public class GetRateCallable implements Callable<ExchangeRate> {

	private static final String google = "http://www.google.com/ig/calculator?hl=en&q=";
	private String from;
	private String to;

	public GetRateCallable(String from, String to) {
		this.from = from;
		this.to = to;
	}

	@Override
	public ExchangeRate call() throws Exception {
		double total = 1d;
		String baseCurrency = from;
		String termCurrency = to;
		String charset = "UTF-8";

		URL url = new URL(google + encode(total + baseCurrency + "=?" + termCurrency));
		log.trace("URL : {}", url.toExternalForm());
		Reader reader = new InputStreamReader(url.openStream(), charset);

		Gson gson = new Gson();
		Result result = gson.fromJson(reader, Result.class);

		// Get the value without the term currency.
		String amount = result.getRhs().split("\\s+")[0];
		log.info("Rate : {} ", amount);
		return new ExchangeRate(from, to, Double.parseDouble(amount), new Date().getTime());
	}

	public static String encode(String input) {
		StringBuilder resultStr = new StringBuilder();
		for (char ch : input.toCharArray()) {
			if (isUnsafe(ch)) {
				resultStr.append('%');
				resultStr.append(toHex(ch / 16));
				resultStr.append(toHex(ch % 16));
			} else {
				resultStr.append(ch);
			}
		}
		return resultStr.toString();
	}

	private static char toHex(int ch) {
		return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
	}

	private static boolean isUnsafe(char ch) {
		if (ch > 128 || ch < 0)
			return true;
		return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
	}

	static class Result {
		private String lhs;
		private String rhs;
		private String error;
		private String icc;

		public String getLhs() {
			return lhs;
		}

		public String getRhs() {
			return rhs;
		}

		public void setLhs(String lhs) {
			this.lhs = lhs;
		}

		public void setRhs(String rhs) {
			this.rhs = rhs;
		}

		public String getError() {
			return error;
		}

		public void setError(String error) {
			this.error = error;
		}

		public String getIcc() {
			return icc;
		}

		public void setIcc(String icc) {
			this.icc = icc;
		}

	}
}
